<!--
 * 关系选择器
 * @作者: 陈老师儿~
 * @手机: 18560000860
 -->
<template>
    <view class="pure-relation-select" :class="classes" :style="styles">
        <!-- 使用 pure-popup 组件，在支付宝小程序中 swiper 高度会塌陷为0，只能自行实现弹窗了 -->
        <!-- Overlay -->
        <pure-overlay :show="show && overlay" @close="handleOverlayClose"></pure-overlay>

        <view class="pure-relation-select-wrapper">
            <!-- Header -->
            <view class="pure-relation-select-header">
                <!-- Title -->
                <view class="pure-relation-select-title">
                    <slot name="title" v-if="$slots.title"></slot>
                    <text v-else>{{ title }}</text>
                </view>

                <!-- Close -->
                <view class="pure-relation-select-close" v-if="close" :hover-clas="hoverClass" @tap="handleClose">
                    <slot name="close" v-if="$slots.close"></slot>
                    <pure-icon :name="closeIcon" v-else></pure-icon>
                </view>
            </view>

            <!-- Body -->
            <view class="pure-relation-select-body">
                <!-- Tabs -->
                <view class="pure-relation-select-tabs">
                    <scroll-view scroll-y class="pure-relation-select-tabs-scroll-view">
                        <view class="pure-relation-select-tabs-list">
                            <view class="pure-relation-select-tab" v-for="(_tab, _index) in options" :key="_index" :class="getTabClasses(_tab, _index)" @tap="handleTabClick(_tab, _index)">
                                <text class="pure-relation-select-tab-label" v-if="_tab?.[labelKey]">{{ _tab?.[labelKey] }}</text>
                                <text class="pure-relation-select-tab-sublabel" v-if="_tab?.[subLabelKey]">{{ _tab?.[subLabelKey] }}</text>
                            </view>
                        </view>
                    </scroll-view>
                </view>

                <swiper class="pure-relation-select-swiper" vertical :duration="200" :current="tabCurrent" @change="handleSwiperChange">
                    <!-- Swiper Item -->
                    <swiper-item class="pure-relation-select-swiper-item" v-for="(_tab, _index) in options" :key="_tab.value">
                        <view class="pure-relation-select-options-body">
                            <scroll-view class="pure-relation-select-scroll-view" :scroll-x="false" :scroll-y="true">
                                <!-- Options -->
                                <view class="pure-relation-select-options">
                                    <!-- Option -->
                                    <view
                                        class="pure-relation-select-option"
                                        v-for="(_item, _current) in _tab[childrenKey]"
                                        :key="_current"
                                        :class="optionClasses(_tab, _index, _current, _item)"
                                        @tap="handleOptionClick(_tab, _index, _current, _item)"
                                        :hover-class="hoverClass"
                                    >
                                        <text class="pure-relation-select-option-text">{{ _item?.[textKey] }}</text>
                                        <view class="pure-relation-select-option-icon">
                                            <pure-icon :name="selectedIcon"></pure-icon>
                                        </view>
                                    </view>
                                </view>
                            </scroll-view>
                        </view>
                    </swiper-item>
                </swiper>
            </view>

            <!-- Footer -->
            <view class="pure-relation-select-footer">
                <slot name="footer" v-if="$slots.footer"></slot>
                <view class="pure-relation-select-footer-btn" v-else-if="showBtn">
                    <pure-button
                        v-bind="btnOpts"
                        :class="btnClass"
                        :text="btnText"
                        @onClick="handleConfirm"
                        @getPhoneNumber="handleGetPhoneNumber"
                        @getuserinfo="handleGetUserInfo"
                        @getUserInfo="handleGetUserInfo"
                        @error="handleError"
                        @opensetting="handleOpenSetting"
                        @launchapp="handleLaunchApp"
                        @contact="handleContact"
                        @chooseavatar="handleChooseAvatar"
                        @agreeprivacyauthorization="handleAgreePrivacyAuthorization"
                        @addgroupapp="handleAddGroupApp"
                        @chooseaddress="handleChooseAddress"
                        @chooseinvoicetitle="handleChooseInvoiceTitle"
                        @subscribe="handleSubscribe"
                        @login="handleLogin"
                        @im="handleIM"
                    ></pure-button>
                </view>
            </view>
        </view>
    </view>
</template>

<script>
    import props from "./props.js";
    export default {
        options: {
            // 将自定义节点设置成虚拟的
            // 头条、飞书：因为合并后丢失事件和 'provide/inject'
            // 京东：因为合并后不能合并外层 'class'
            // 百度：因为合并后会在控制台疯狂报警告
            // #ifndef MP-TOUTIAO || MP-LARK || MP-JD || MP-BAIDU
            virtualHost: true,
            // #endif

            // 组件样式隔离
            styleIsolation: "apply-shared",

            // 允许使用多个插槽
            multipleSlots: true,
        },
        props: props,
        emits: [
            "confirm",
            "onClick",
            "close",
            "getphonenumber",
            "getuserinfo",
            "error",
            "opensetting",
            "launchapp",
            "contact",
            "chooseavatar",
            "agreeprivacyauthorization",
            "addgroupapp",
            "chooseaddress",
            "chooseinvoicetitle",
            "subscribe",
            "login",
            "im",
        ],
        data() {
            return {
                // 显示状态
                status: "hide",
                // 选中的 Tab 索引
                tabCurrent: 0,
                // 选中的选项索引
                childrenCurrent: [],
            };
        },
        computed: {
            // classes
            classes() {
                const classes = [];

                // 显示状态类名
                classes.push(`pure-relation-select-${this.status}`);

                // 显示安全区
                if (this.safeBottom) classes.push("pure-relation-select-safe-bottom");

                return classes;
            },

            // styles
            styles() {
                const styles = [];
                return styles;
            },
        },
        watch: {
            // 监听显示状态
            async show(val) {
                if (val) {
                    this.status = "before-show";
                    await this.$nextTick();
                    await this.sleep(20);
                    this.status = "to-show";

                    // 显示时需重新初始化一下 pure-tabs
                    // 这是因为隐藏是设置了 display: none，导致 pure-tabs 不能正常设置指示器的位置
                    await this.$nextTick();
                    await this.sleep(200);
                    this.$refs.PureTabsRef?.init?.();
                } else {
                    this.status = "before-hide";
                    await this.$nextTick();
                    await this.sleep(20);
                    this.status = "to-hide";
                }
            },
        },
        async mounted() {
            // 初始化状态
            this.status = this.show ? "show" : "hide";
        },
        methods: {
            // 选项点击事件
            async handleOptionClick(tab, tabIndex, optionIndex, option) {
                // 禁用了
                if (option?.disabled) return;

                // 获取选中项下标
                const tabIndexes = this.getTabIndexes(tabIndex);

                // 提交选择事件
                this.$emit("onClick", {
                    option: tab,
                    optionIndex: tabIndex,
                    childIndex: optionIndex,
                    child: option,
                    isChecked: tabIndexes.indexOf(optionIndex) !== -1,
                });

                // 更新分类选中下标
                this.updateTabIndexes(tabIndexes, optionIndex, tabIndex);
            },

            // 确认
            handleConfirm() {
                this.$emit("confirm", this.getSelectedItems());
            },

            // 获取分类选中项下标
            getTabIndexes(tabIndex) {
                // 选中项的下标集
                const indexes = this.childrenCurrent;

                // 当前分类对应选中的下标
                let tabIndexes = indexes[tabIndex];
                if (tabIndexes === undefined) tabIndexes = [];
                else if (typeof tabIndexes === "number") tabIndexes = [tabIndexes];

                return tabIndexes;
            },

            // 更新分类选中下标
            updateTabIndexes(tabIndexes = [], optionIndex, tabIndex) {
                // 多选
                if (this.multiple) {
                    if (tabIndexes.indexOf(optionIndex) === -1) tabIndexes.push(optionIndex);
                    else tabIndexes.splice(tabIndexes.indexOf(optionIndex), 1);
                    this.childrenCurrent[tabIndex] = tabIndexes;
                    return;
                }

                // 单选
                tabIndexes = [optionIndex];
                this.childrenCurrent[tabIndex] = tabIndexes;
            },

            // 获取选中项数据
            getSelectedItems() {
                // 多选
                if (this.multiple) {
                    const tabs = [];

                    this.options.forEach((_item, _index) => {
                        // 获取分类选中项数据
                        const tab = this.getTabSelectedItems(_index);
                        tabs.push(tab);
                    });

                    return tabs;
                }

                return this.getTabSelectedItems(this.tabCurrent);
            },

            // 获取分类选中项数据
            getTabSelectedItems(tabIndex) {
                // tab 数据
                const tab = this.options[tabIndex];

                // 默认选中项数据
                const selectedChildren = [];

                // 获取选中项下标
                const tabIndexes = this.getTabIndexes(tabIndex);

                // 循环下标
                tabIndexes.forEach((_index) => {
                    const option = tab[this.childrenKey]?.[_index];
                    selectedChildren.push(option);
                });

                // 选中项数据
                tab.selectedChildren = selectedChildren;

                return tab;
            },

            // 选项类名
            optionClasses(tab, tabIndex, optionIndex, option) {
                const classes = [];

                // 获取选中项下标
                const tabIndexes = this.getTabIndexes(tabIndex);

                // 是否选中
                if (tabIndexes?.indexOf(optionIndex) !== -1) classes.push("pure-relation-select-option-selected");

                // 是否禁用
                if (option?.disabled) classes.push(this.disabledClass);

                return classes;
            },

            // Tab 类名
            getTabClasses(tab, index) {
                const classes = [];

                // 是否激活
                if (index === this.tabCurrent) classes.push("pure-relation-select-tab-active");

                return classes;
            },

            // 切换
            handleSwiperChange(e) {
                this.tabCurrent = e.detail.current;
            },

            // Tab点击事件
            handleTabClick(tab, index) {
                // 更新 Swiper Current
                this.tabCurrent = index;
            },

            // 关闭事件
            handleClose() {
                this.$emit("close");
            },

            // 遮罩点击事件
            handleOverlayClose() {
                // 点击遮罩不可关闭
                if (this.stopCloseOnClickOverlay) return;
                this.$emit("close");
            },

            // 同步延时
            sleep(time = 50) {
                return new Promise((resolve) => {
                    let timer = setTimeout(() => {
                        clearTimeout(timer);
                        resolve();
                    }, time);
                });
            },

            // getPhoneNumber
            handleGetPhoneNumber(e) {
                // 禁用了
                if (this.disabled) return;

                this.$emit("getphonenumber", e);
            },

            // getUserInfo
            handleGetUserInfo(e) {
                // 禁用了
                if (this.disabled) return;

                this.$emit("getuserinfo", e);
            },

            // error
            handleError(e) {
                // 禁用了
                if (this.disabled) return;

                this.$emit("error", e);
            },

            // openSetting
            handleOpenSetting(e) {
                // 禁用了
                if (this.disabled) return;

                this.$emit("opensetting", e);
            },

            // launchApp
            handleLaunchApp(e) {
                // 禁用了
                if (this.disabled) return;

                this.$emit("launchapp", e);
            },

            // contact
            handleContact(e) {
                // 禁用了
                if (this.disabled) return;

                this.$emit("contact", e);
            },

            // chooseAvatar
            handleChooseAvatar(e) {
                // 禁用了
                if (this.disabled) return;

                this.$emit("chooseavatar", e);
            },

            // agreePrivacyAuthorization
            handleAgreePrivacyAuthorization(e) {
                // 禁用了
                if (this.disabled) return;

                this.$emit("agreeprivacyauthorization", e);
            },

            // addGroupApp
            handleAddGroupApp(e) {
                // 禁用了
                if (this.disabled) return;

                this.$emit("addgroupapp", e);
            },

            // chooseAddress
            handleChooseAddress(e) {
                // 禁用了
                if (this.disabled) return;

                this.$emit("chooseaddress", e);
            },

            // chooseInvoiceTitle
            handleChooseInvoiceTitle(e) {
                // 禁用了
                if (this.disabled) return;

                this.$emit("chooseinvoicetitle", e);
            },

            // subscribe
            handleSubscribe(e) {
                // 禁用了
                if (this.disabled) return;

                this.$emit("subscribe", e);
            },

            // login
            handleLogin(e) {
                // 禁用了
                if (this.disabled) return;

                this.$emit("login", e);
            },

            // im
            handleIM(e) {
                // 禁用了
                if (this.disabled) return;

                this.$emit("im", e);
            },
        },
    };
</script>

<style scoped>
    @import "./style.css";
</style>
